using UnityEngine;
using System.Collections;
using System;
using System.Collections.Generic;
public interface ITypeEventSystem
{
    public IUnRegisterEventClass RegisterEvent<T>(Action<T> action);
    public void UnRegisterEvent<T>(Action<T> action);
    public void TriggerEvent<T>(T parameter = default(T));
}
public class TypeEventSystem : ITypeEventSystem
{
    public static TypeEventSystem Instance = new TypeEventSystem();
    private Dictionary<Type, IEventClass> eventDic = new Dictionary<Type, IEventClass>();

    private TypeEventSystem()
    {

    }

    IUnRegisterEventClass ITypeEventSystem.RegisterEvent<T>(Action<T> action)
    {
        Type type = typeof(T);
        if (!eventDic.ContainsKey(type))
        {
            eventDic.Add(type, new EventClass<T>());
        }
        ((EventClass<T>)eventDic[type]).OnEvent += action;
        return new UnRegisterEventClass<T>(action);
    }

    public void UnRegisterEvent<T>(Action<T> action)
    {
        Type type = typeof(T);
        if (eventDic.ContainsKey(type))
        {
            ((EventClass<T>)eventDic[type]).OnEvent -= action;
        }
    }
    void ITypeEventSystem.TriggerEvent<T>(T parameter)
    {
        Type type = typeof(T);
        if (eventDic.ContainsKey(type))
        {
            ((EventClass<T>)eventDic[type]).TriggerEvent(parameter);
        }
    }
}
public interface IEventClass
{
    //void OnEvent();
}
public class EventClass<T> : IEventClass
{
    public event Action<T> OnEvent;

    public void TriggerEvent(T parameter)
    {
        OnEvent?.Invoke(parameter);
    }
}
public class UnRegisterEventClass<T> : IUnRegisterEventClass
{
    private Action<T> action;
    public void UnRegisterEvent()
    {
        TypeEventSystem.Instance.UnRegisterEvent(action);
    }
    public UnRegisterEventClass(Action<T> action)
    {
        this.action = action;
    }
}
public interface IUnRegisterEventClass
{
    public void UnRegisterEvent();
}
public interface ICanRegisterEvent
{

}
public interface ICanTriggerEvent
{

}
public static class TypeEventSystemExtension
{
    public static IUnRegisterEventClass RegisterEvent<T>(this ICanRegisterEvent canRegisterEvent, Action<T> action)
    {
        return (TypeEventSystem.Instance as ITypeEventSystem).RegisterEvent<T>(action);
    }
    public static void TriggerEvent<T>(this ICanTriggerEvent canTriggerEvent, T parameter)
    {
        (TypeEventSystem.Instance as ITypeEventSystem).TriggerEvent<T>(parameter);
    }
    public static void UnRegisterEventWhenBeDistroyed(this IUnRegisterEventClass unRegisterEventClass, GameObject gameObject)
    {
        if (!gameObject.TryGetComponent<UnRegisterEventWhenBeDestroiedMono>(out var unRMono))
        {
            unRMono = gameObject.AddComponent<UnRegisterEventWhenBeDestroiedMono>();
        }
        unRMono.Add(unRegisterEventClass);
    }
}
public class UnRegisterEventWhenBeDestroiedMono : MonoBehaviour
{
    private HashSet<IUnRegisterEventClass> unRegisterEventClasses = new HashSet<IUnRegisterEventClass>();
    public void Add(IUnRegisterEventClass unRegisterEventClass)
    {
        unRegisterEventClasses.Add(unRegisterEventClass);
    }
    private void OnDestroy()
    {
        foreach (var unRegisterEventClass in unRegisterEventClasses)
        {
            unRegisterEventClass.UnRegisterEvent();
        }
        unRegisterEventClasses.Clear();
    }
}